﻿
#include "avatar_node.h"
#include <assimp/scene.h> // 包含Assimp的场景结构体
#include <dx/core/dx_math.h>
#include <klog.h>

using namespace DirectX;

namespace ifire::game {
static const char* ASSIMP_PRE_NODE = "$AssimpFbx$";

AvatarNode::AvatarNode(AvatarNode* _parent, int child_count, ikit::sstr _name,
    const DirectX::XMFLOAT4X4& trans_mat, const DirectX::XMFLOAT3& _position,
    const DirectX::XMFLOAT4& _rotation)
    : parent(_parent)
    , name(_name)
    , children(child_count)
    , transform_matrix(trans_mat)
    , position(_position)
    , rotation(_rotation) {}

AvatarNode::~AvatarNode() {
  // 递归删除所有子节点
  for (AvatarNode* child : children) {
    delete child;
  }
  children.clear(); // 清空子节点列表
}

AvatarNode* AvatarNode::CreateFrom(AvatarNode* parent_node, const aiNode* node,
    const DirectX::XMFLOAT4X4& parent) {
  // 获得当前的transform
  XMFLOAT4X4 transformation(dx::DxMath::ConvertMatrix(node->mTransformation));

  // 获得名称
  ikit::sstr name(node->mName.C_Str());

  // 检查名称中是否拥有"$AssimpFbx$"
  while (true) {
    // 如果没有，跳出循环
    if (name.index_of(ASSIMP_PRE_NODE) == -1 || node->mChildren == nullptr) {
      break;
    }

    // 得到下一个Node
    const aiNode* next = node->mChildren[0];
    // 与下一个Node进行计算
    auto parent_m = XMLoadFloat4x4(&transformation);
    XMFLOAT4X4 next_mat(dx::DxMath::ConvertMatrix(next->mTransformation));
    auto next_m = XMLoadFloat4x4(&next_mat);
    // 进行乘法，注意是右乘，所以父级在右边
    // （其实这个关系不是很大，因为Assimp的处理，导致下一个Node只能是单位矩阵）
    auto final_m = XMMatrixMultiply(next_m, parent_m);

    // 替换掉当前的项目
    XMStoreFloat4x4(&transformation, final_m);
    name = ikit::sstr(next->mName.C_Str());
    node = next;
  }

  // 目前已经得到了正确的变换矩阵，这样就可以根据矩阵分解出旋转和位移

  // 获得当前这个节点的变换
  auto parent_mat = XMLoadFloat4x4(&parent);
  auto node_trans_mat = XMLoadFloat4x4(&transformation);
  auto current_mat = XMMatrixMultiply(node_trans_mat, parent_mat);

  // 逆向计算该节点相对于父节点的矩阵
  auto inv_parent_mat = XMMatrixInverse(nullptr, parent_mat);
  auto relative_mat = XMMatrixMultiply(current_mat, inv_parent_mat);
  // 分离提取项目
  XMVECTOR positionVec;
  XMVECTOR rotationQuat;
  XMVECTOR scaleVec;
  XMMatrixDecompose(&scaleVec, &rotationQuat, &positionVec, relative_mat);
  // 将分离的项目设置到相应的节点
  XMFLOAT3 position;
  XMFLOAT4 rotation;
  XMStoreFloat3(&position, positionVec);
  XMStoreFloat4(&rotation, rotationQuat);

  // 返回项目
  auto item = new AvatarNode(parent_node, node->mNumChildren, name,
      transformation, position, rotation);

  KLOG("Create Avatar Node: %s, Parent %s", name.c_str(),
      parent_node ? parent_node->name.c_str() : "NULL");
  KPRINT("POS:");
  ikit::print_vec3(position);
  KPRINT("ROT:");
  ikit::print_eular(rotationQuat);

  // 如果有子项目，创建子项目
  XMFLOAT4X4 current;
  XMStoreFloat4x4(&current, current_mat);
  for (unsigned int i = 0; i < node->mNumChildren; i++) {
    item->children[i] = CreateFrom(item, node->mChildren[i], current);
  }

  return item;
}

} // namespace ifire::game